/**
 * 
 */
package servlet;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import container.MyContainer;
import container.ProcessorInfo;


import logging.Level;
import logging.Logger;
import net.kaixinpig.processor.HelloProcessor;


/**
 * @author think
 *
 */
public class DispatcherServlet extends HttpServlet {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final Logger LOGGER = Logger.getLogger(DispatcherServlet.class.getName());

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void service(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
			throws ServletException, IOException {
		
			String requestURI = httpServletRequest.getPathInfo();
			LOGGER.info("requestURI:"+requestURI);
			
			MyContainer myContainer = MyContainer.getInstance();
			Map<String, ProcessorInfo> processorInfoMap = myContainer.getProcessorInfoMap();
			Iterator<String> iterator = processorInfoMap.keySet().iterator();
			ProcessorInfo processorInfo = null;
			while(iterator.hasNext()){
				String regex = iterator.next();
				if(requestURI.matches(regex)){
					LOGGER.info("get processorInfo success");
					processorInfo = processorInfoMap.get(regex);
					break;
				}
			}
			
			if(processorInfo!=null){
				Method method = processorInfo.getMethod();
				Class<?> targetClazz = method.getDeclaringClass();
				String targetClazzName = targetClazz.getName();
				LOGGER.info("targetClazzName "+targetClazzName);
				
				try {
					Object targetObject = getTargetObject(myContainer,targetClazzName,targetClazz);
					setWebContext(targetClazz, targetObject ,httpServletRequest,httpServletResponse);
					setMethodContext(targetClazz, targetObject ,processorInfo,httpServletRequest);
				} catch (Exception e) {
					LOGGER.log(Level.WARN, "", e);
				}
				
			}
			
		
	}
	
	/**
	 * 设置方法的上下文并执行方法
	 * @param targetClazz
	 * @param targetObject
	 * @param processorInfo
	 * @param httpServletRequest 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	private void setMethodContext(Class<?> targetClazz, Object targetObject,
			ProcessorInfo processorInfo, HttpServletRequest httpServletRequest) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		Method method = processorInfo.getMethod();
		//Class<?>[] parameterTypes = processorInfo.getParameterTypes();
		String[] parameterNames = processorInfo.getParameterNames();
		String[] values = processorInfo.getDefaultValues();
		int index = 0;
		for(String parameterName:parameterNames){
			String vv = httpServletRequest.getParameter(parameterName);
			if(vv!=null){
				values[index] = vv;
			}
			index++;
			
		}
		method.invoke(targetObject, values);
	}

	/**
	 * 设置processor的父类web上下文
	 * @param targetClazz
	 * @param httpServletRequest
	 * @param httpServletResponse
	 * @throws NoSuchMethodException 
	 * @throws SecurityException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	private void setWebContext(Class<?> targetClazz,Object targetObject ,
			HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		Class<?> supperTargetClazz = targetClazz.getSuperclass();
		//setRequest
		Method requestMethod = supperTargetClazz.getDeclaredMethod("setRequest", HttpServletRequest.class);
		requestMethod.invoke(targetObject, httpServletRequest);
		//setResponse
		Method responseMethod = supperTargetClazz.getDeclaredMethod("setResponse", HttpServletResponse.class);
		responseMethod.invoke(targetObject, httpServletResponse);
	}

	/**
	 *  从容器中取出processor对象，如果不存在，则创建
	 * @param myContainer
	 * @param targetClazzName
	 * @param targetClazz
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	private Object getTargetObject(MyContainer myContainer,String targetClazzName,Class<?> targetClazz) throws InstantiationException, IllegalAccessException{
		Object targetObject = myContainer.getBean(targetClazzName);
		if(targetObject ==null){
				LOGGER.info("create processor ["+targetClazzName+"]");
				Object obj = targetClazz.newInstance();
				myContainer.regBean(targetClazzName, obj);
				targetObject = obj;
		}
		return targetObject;
	}
	
	

}
